/*
 * Computer Graphics:  Andrew Hanson, Indiana University
 * GLUT  Graphics Exercise Template 
 *

 cc -o template.linux template.c -lglut -lGLU -lGL -lm

 *
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>

/* Local Graphics Definitions. Also in /l/b481/include, /l/b581/include */
#include "defs.h"

/*  double y0,y1;   math.h conflict */

/***************************************************************/
/******************** MY GLOBAL VARIABLES **********************/
/***************************************************************/

#define MID_TERM_MODE 1

int drawingMode= MID_TERM_MODE;

int mouseButtons = 0;

int MouseModifiers = 0;

int X=0, Y=0, dX=0, dY=0;

int main_window;
int main_height, main_width;

int fixed_point_x = 1, fixed_point_y = 1;
GLboolean refresh_display= GL_TRUE;

float mat[16];

/***************************************************************/
/*********************** MY FUNCTIONS    ***********************/
/***************************************************************/

void drawRects() {

	int large_rect_size = fmin(main_height, main_width) - 250;

	glColor3f(1.0, 1.0, 1.0);
	int x_init = 50, y_init = large_rect_size+50;
	glRecti(x_init, y_init, y_init, x_init);

	glColor3f(0.0, 0.0, 0.0);
	int i, j, rect_side = 20;
	for (i = 0; i < large_rect_size; i += rect_side*2) {
		x_init = (i % 2) == 0 ? 50 : 50 + rect_side;
		y_init = (i % 2) == 0 ? large_rect_size+50 : large_rect_size + 50
				- rect_side;
		for (j = 0; j < large_rect_size; j += rect_side*2) {
			glRecti(x_init + i, y_init - j, x_init + i + rect_side, y_init - j
					- rect_side);
		}
	}
}

void scaleObject() {

	// get the object back to initial place
	glTranslatef(fixed_point_x, fixed_point_y, 0.0);

	// scale it
	glScalef((float)(fixed_point_x - X)/fixed_point_x + 1,
			(float)(fixed_point_y - X)/fixed_point_y + 1, 1.0);

	fprintf(stderr, "Scale X = %f, scale Y = %f\n", (float)(fixed_point_x - X)/fixed_point_x + 1, (float)(fixed_point_y - X)/fixed_point_y + 1);

	// get the object to origin
	glTranslatef(-fixed_point_x, -fixed_point_y, 0.0);
}

void drawUsingMethodOne() {
	glMatrixMode(GL_MODELVIEW);
	if (refresh_display == GL_FALSE && mouseButtons == 0x1) {
		glGetFloatv(GL_MODELVIEW_MATRIX,mat);
		glLoadIdentity();

		scaleObject();
		glMultMatrixf(mat);
	} else {
		glLoadIdentity();
	}

	

	drawRects();
	glColor3f(0.8, 0.6, 0.4);
	glPointSize(5.0);
	glBegin(GL_POINTS);
	glVertex2i(fixed_point_x, fixed_point_y);
	glEnd();
}

/***************************************************************/
/*********************** MOUSE CALLBACKS ***********************/
/***************************************************************/

/* Mouse Button  UP/DOWN  or DOWN/UP transition only */
void mouse(int button, int state, int x, int y) {
	X = x;
	Y = main_height - y - 1; /* Invert to right-handed system */
	button = (1 << button);

	MouseModifiers = glutGetModifiers();
	/* bitmask with GLUT_ACTIVE_SHIFT, GLUT_ACTIVE_CTRL, GLUT_ACTIVE_ALT */

	if (state == GLUT_DOWN)
		mouseButtons |= button;
	else
		mouseButtons &= (~(button));

	if (drawingMode == MID_TERM_MODE && state == GLUT_DOWN) {
		fixed_point_x = X;
		fixed_point_y = Y;
	}

	fprintf(stderr,"Comment this out: mouse buttons = [%d], modifiers = [%d] \n\
          state = %s, mouse at (%d,%d)\n",
	mouseButtons, MouseModifiers,
	state == GLUT_UP? "Just Up":"Just Down",x,y);

	glutPostRedisplay();
}

/* Mouse motion WHILE BUTTON DOWN  */
/*  COMPLAINS  if you call glutGetModifiers()  here!! */
void motion(int x, int y) {
	fprintf(stderr,"Comment this out: mouse at (%d,%d)\n\
          mouse buttons = [%d], modifiers = [%d]\n",
	x,y, mouseButtons, MouseModifiers);
	X = x;
	Y = main_height - y - 1; /* Invert to right-handed system */

	switch (mouseButtons) {
	case 0x1: /* Left Mouse Button   */
		break;
	case 0x2: /* Middle Mouse Button */
		break;
	case 0x4: /* Right Mouse Button  */
		break;
	}
	glutPostRedisplay();

}

/* Mouse motion WHILE ALL BUTTONS UP  */
/*  COMPLAINS  if you call glutGetModifiers()  here!! */
void passive(int x, int y) {
	X = x;
	Y = main_height - y - 1;

	glutPostRedisplay();
}

/* Handle Keyboard */
void keyboard(unsigned char key, int x, int y) {
	/*  Option: To force all lower case */
	/* if (key >= 'A' && key <= 'Z') key = (key-'A') + 'a'; */

	switch (key) {
	case 'h':
		fprintf(stderr,"Help: goes here.\n");
		break;
	case 'r':
		refresh_display = GL_TRUE;
		break;
	case '1':
		drawingMode = MID_TERM_MODE;
		refresh_display = GL_TRUE;
		break;
	case 'q':
	case 27: /* 27 -> ESC */
		fprintf(stderr,"Normal Exit.\n");
		exit(EXIT_SUCCESS);
		break;
	default:
		fprintf(stderr,"Unhandled key: %c [%d] \n",key,key);
	}

	glutPostRedisplay();
}

/***************************************************************/
/************************** INIT GL ****************************/
/***************************************************************/

void initGL() {
	glClearColor(0.0, 0.0, 0.0, 0.0);
}

/***************************************************************/
/************************ DRAW STUFF ***************************/
/***************************************************************/

void drawObjs() {
	switch (drawingMode) {
	case MID_TERM_MODE:
		drawUsingMethodOne();
		break;
	}
	//glColor3f(0.9,0.8,0.4);
	//glRecti(200,50,300,450); 
	//drawRects();


}

/***************************************************************/
/************************ GLUT STUFF ***************************/
/***************************************************************/

void reshape(int w, int h) {
	fprintf(stderr,"Comment this out: reshape(%d,%d) \n",w,h);
	w = Max(w,128);
	h = Max(h,128);
	main_height = h;
	main_width = w;
	glutReshapeWindow(w, h);
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluOrtho2D(0.0, (double)w-1, 0.0, (double)h-1);

	glMatrixMode(GL_MODELVIEW);
}

void visibility(int state) {
	/* May also want to check PARTIAL DAMAGE that
	 does not result in a call to the visibility callback:
	 if (glutLayerGet(GLUT_NORMAL_DAMAGED)) {
	 redraw = TRUE; }
	 */
	fprintf(stderr,"Comment this out: visibility: %s\n",
	(state==GLUT_VISIBLE)?"visible":"invisible");
	if (state == GLUT_VISIBLE) {
		glutPostRedisplay();
	}
}

void display(void) {
	fprintf(stderr,"Comment this out: display\n");

	glClear(GL_COLOR_BUFFER_BIT);

	drawObjs();

	glutSwapBuffers();
}

/***************************************************************/
/**************************** MAIN *****************************/
/***************************************************************/

int main(int argc, char **argv) {
	/* GLUT Initialization */
	glutInit(&argc, argv);
	glutInitWindowSize(500, 500);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

	/* Create a new window and give a title to it */
	main_window = glutCreateWindow("CHANGE THIS TITLE!!!!!!!");

	/* Initialize OpenGL stuff */
	initGL();

	/* Post Event Handlers */
	glutReshapeFunc(reshape);
	glutVisibilityFunc(visibility);
	glutDisplayFunc(display);
	glutMouseFunc(mouse);
	glutMotionFunc(motion);
	glutPassiveMotionFunc(NULL);

	glutKeyboardFunc(keyboard);
	fprintf(stderr,"Press ESC or 'q' to Exit.\n");

	glutIdleFunc(NULL);

	glutMainLoop();

	return (EXIT_SUCCESS);
}
